#ifndef _TECAN_H
#define _TECAN_H

#include <iostream>
#include <pthread.h>
#include <unistd.h>

#define MAX_TECAN_BUFF_LEN 1024
#define SID_TECAN 0x01


#define SOCA_FRAME_TAIL 0x03
#define SOCA_FRAME_HEADER 0x02
#define SEQNUM 0x31
#define SOCAID 0x33

typedef enum 
{
   DEV_CMD_BLOCK,
   STR_CMD_BLOCK,
   GRP_CMD_BLOCK
}en_cmd_type;

typedef struct _DevCmdBlock
{
   char devId;
   char frameType;
   char data;
}DevCmdBlock;

typedef struct _StrCmdBlock
{
   char data0;
   int data1;
}StrCmdBlock;

typedef struct _GrpCmdBlock
{
   
}GrpCmdBlock;

typedef struct _tecanCmdBlock
{
   unsigned char blockType;
   union {
      DevCmdBlock stDevCmd;
      StrCmdBlock stStrCmd;
      GrpCmdBlock stGrpCmd;
   }un_cmdBlock;
   struct _tecanCmdBlock * next;
   struct _tecanCmdBlock * child;
}tecanCmdBlock;

typedef enum 
{
   SYS_ACK_RES,
   CMD_STR_COMP_RES,
   SYS_QUERY_RES,
   DEV_QUERY_RES
}en_res_type;

typedef struct _resSysAck
{
   char cmdId;
}resSysAck;

typedef struct _resCmdStrComp
{
   char cmdId;
   char devId;
   unsigned char devStatus[4];
}resCmdStrComp;

typedef struct _resSysQuery
{
   char cmdId;
   char error_code[4];
   char data[128];
}resSysQuery;

typedef struct _resDevQuery
{
   char cmdId;
   char devId;
   char devSatus[4];
   char data[128];
}resDevQuery;

typedef struct _tecanRecvMsg
{
   unsigned char resType;
   union {
      resSysAck stResSysAck;
      resCmdStrComp stResCmdStrComp;
      resSysQuery stResSysQuery;
      resDevQuery stResDevQuery;
   }un_res;
   struct _tecanRecvMsg * next;
}tecanRecvMsg;

typedef enum
{
   tecan_not_init,
   tecan_idle,
   tecan_waiting_ack,
   tecan_waiting_res,
}en_tecan_status;

#define TECAN_STX 0x02
#define TECAN_TAIL 0x03

typedef void (*competeCallBack)(int statusCodeIn,int errorNumIn,int sid, int moduleId);

class CTecan
{
private:
   unsigned char m_recvBuff[MAX_TECAN_BUFF_LEN];
   int m_recvLen;
   int m_currStatus;
   pthread_mutex_t m_memMutex;
   int m_exitThreadFlag;
   competeCallBack m_funcComplteCB;
   int m_liquid_detected;
   int m_msgSrc;
public:
   CTecan();
   virtual ~CTecan();

   void addToBuff(unsigned char* ptrBuff, int len);

   static int parseFrame(unsigned char* ptrBuff, int len,tecanRecvMsg** msgOut);

   static void encap_cmd_str(tecanCmdBlock * ptrBlockList,unsigned char * buffOut, int* lenOut);

   void setCurrStatus(int statusIn);
   int getCurrStatus(void);

   static void * funcProcThread(void * paramIn);

   void setInitSOCAStr(int liquidType,unsigned char * buffOut,int * lenOut);
   void setInitAdp_Z_Str(unsigned char * buffOut,int * lenOut);

   void setZMoveStr(void * moveParamIn, unsigned char * buffOut,int *lenOut);

   void setLoadTipStr(void * tipParamIn,unsigned char * buffOut,int *lenOut);

   void setDropTipStr(void * tipParamIn,unsigned char * buffOut,int *lenOut);
   void setResetAdpStr(unsigned char * buffOut,int *lenOut);
   void actSuckLiquid(void * liquidParamIn, void * canInterFace);

   void actSuckLiquid_ext(void * suckParamIn, void * canInterFace);

   void actSuckLiquid_p(void * suckParamIn, void * canInterFace);
   void actSuckLiquid_p1(void * suckParamIn, void * canInterFace);

   void actDispenseLiquid(void * liquidParamIn, void * canInterFace);

   void encap_tecan_frame(unsigned char * buffInOut,int lenIn,int * lenOut);

   void startRecv(void);

   void setExitFlag(int flagIn);

   int getExitFlag(void);

   int isRecvComplete(void);

   int getRecvLen(void);

   int getBuffData(unsigned char * buffOut,int *lenOut);

   int cmdAct(void * param,void * canInterface);

   int clearBuff(void);   

   void setCompleteCB(competeCallBack ptrFuncIn);


   void actFinish(int statusCode,int errorNum);

   void setLiquidDetect(int isDetected);

   int sendAndWaitAck(unsigned char * strIn, void * canInterface); 

   void setSuckSimpleStr(void * suckParamIn,unsigned char * buffOut,int *lenOut); 

   void setSpitSimpleStr(void * spitParamIn,unsigned char * buffOut,int *lenOut);    

};


typedef struct _cmdThreadParam
{
    CTecan * ptrTecan;
    void * canHanle;
    int opcode;
    void * param;
}cmdThreadParam;

void * funcCmdThread(void * paramIn);

#endif